#include <vector>
#include <iostream>
#include <limits.h>
#include <algorithm>

using namespace std;

int dx[4] = {0, 0, 1, -1}; // 对应下、上、右。左
int dy[4] = {1, -1, 0, 0};

//int maxSize = 0;
bool inArea(vector<vector<int>> &data, int i, int j)
{
  return (i >= 0 && i < data.size()) && (j >= 0 && j < data[0].size());
}

// 因为要相邻点之间的递减关系，因此这个dfs的结构和岛屿问题不同
// 需要dx[4]与dy[4],这样便能在一个dfs()中探究data[row][col]与相邻点递减的关系
int dfs(vector<vector<int>> &data, int row, int col, vector<vector<int>> &memo)
{
  // base case
  int t = 1; // 就算只有遍历[x,y],路径也为1

  if (memo[row][col] > 0) // 有答案
  {
    return memo[row][col];
  }

  // 状态转移
  for (int i = 0; i < 4; i++)
  {
    int xx = dx[i] + row;
    int yy = dy[i] + col;
    // 这题这个条件相当于一个visited数组：data[row][col] > data[xx][yy]
    // 因为若你访问过这个数组data[row][col], 后续你dfs()过程中，若又搜索到[row,col]
    // 此时[row,col]一定比当前访问的节点大，因此是不会重复访问[row,col]节点的
    if (inArea(data, xx, yy) && data[row][col] > data[xx][yy])
    {
      int tmp = dfs(data, xx, yy, memo) + 1;
      if (tmp > t)
      {
        t = tmp;
      }
    }
  }
  memo[row][col] = t; // 保存到备忘录
  return t;
}

int main()
{
  int rows, cols;
  cin >> rows >> cols;
  if (rows == 0 || cols == 0)
  {
    return 0;
  }
  vector<vector<int>> data(rows, vector<int>(cols));
  for (int i = 0; i < rows; i++)
  {
    for (int j = 0; j < cols; j++)
    {
      cin >> data[i][j];
    }
  }

  vector<vector<int>> memo(rows, vector<int>(cols));

  int ans = INT_MIN;
  // 开始dfs找最长水沟
  for (int i = 0; i < rows; i++)
  {
    for (int j = 0; j < cols; j++)
    {
      // 这题每个点出发有可能，所以我们每个点都要开始dfs，最后取他们的最大值
      // 初始化从(0,0)开始出发
      ans = max(ans, dfs(data, i, j, memo));
    }
  }

  cout << ans << endl;

  return 0;
}